// Copyright (C) 2016 All rights reserved.
// Author: liufeng11@letv.com (Liu Feng)
// Description:
#ifndef _SIMILARCHARACTER_H
#define _SIMILARCHARACTER_H

#include "SimilarCharacter.h"
#include "MyFontFeatureExtractor.h"
#include "MySimilarity.h"
#include <queue>
#include <utility>
#include <cstdio>

typedef std::pair<double, unsigned int> mypair;
template<unsigned K>
class SimilarCharacter {
  public:
    SimilarCharacter(Similarity* si, FontFeatureExtractor* ffe);
    void GetTopK(unsigned int charCode, std::vector<mypair>* r);
    void SetSimilarity(Similarity* si);
    void SetFontFeatureExtractor(FontFeatureExtractor* ffe);
    std::vector<mypair> operator()(unsigned int charCode);
  private:
    Similarity* _si;
    FontFeatureExtractor* _ffe;
};

template<unsigned K>
SimilarCharacter<K>::SimilarCharacter(Similarity* si, FontFeatureExtractor* ffe):
  _si(si), 
  _ffe(ffe) {
  }

template<unsigned K>
void SimilarCharacter<K>::SetSimilarity(Similarity* si) {
  _si = si;
}

template<unsigned K>
void SimilarCharacter<K>::SetFontFeatureExtractor(FontFeatureExtractor* ffe) {
  _ffe = ffe;
}



template<unsigned K>
std::vector<mypair> SimilarCharacter<K>::operator()(unsigned int charCode) {
  std::vector<mypair> r;
  GetTopK(charCode, &r);
  return r;
}


template<unsigned K>
void SimilarCharacter<K>::GetTopK(unsigned int charCode, std::vector<mypair>* r) {
  if (!r) return;
  mypair charachters;
  std::priority_queue<mypair> heap;

  FontFeatureExtractor& ffe = *_ffe;
  Similarity& si = *_si;

  // Chinese character's range [0x4e00, 0x9fa5)
  unsigned int iter = 0x4e00;
  unsigned int last = 0x9fa5;

  std::vector<double> f = ffe(charCode);

  while(iter != last) {
    // printf("%04x\n", iter);
    // printf("\x1b[1A");
    try {
      if (charCode == iter) {
        ++iter;
        continue;
      }
      std::vector<double> f0 = ffe(iter);
      double sim = si(f, f0);


      if (!heap.empty()) {
        mypair pair = heap.top();
        if (sim < pair.first) {
          heap.push(std::make_pair(sim, iter));
        }
      }
      else {
        heap.push(std::make_pair(sim, iter));
      }

      if (heap.size() > K) heap.pop();
    } 
    catch(...) {
    }

    ++iter;
  }


  std::vector<mypair>& v = *r;
  v.resize(heap.size());

  for (int i = heap.size()-1; i >= 0; --i) {
    v[i] = heap.top();
    heap.pop();  
  }
}

#endif //SIMILARCHARACTER_H
